package com.fs.generator.ui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Vector;

import javax.swing.AbstractListModel;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.fs.generator.DefaultCodeGeneratorFactory;
import com.fs.generator.ui.jdbc.JDBCAdapter;
import com.fs.generator.ui.jdbc.JDBConnect;
import com.fs.generator.ui.jdbc.dialect.MetadataDialect;
import com.fs.generator.ui.jdbc.dialect.MysqlMetadataDialectImpl;
import com.fs.generator.ui.jdbc.dialect.OracleMetadataDialectImpl;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class Generator extends JPanel {

	private static final long serialVersionUID = 1L;
	private static final int PREFERRED_WIDTH = 1000;
	private static final int PREFERRED_HEIGHT = 640;

	private JDBConnect jdbConnect;

	private JDBCAdapter dt;

	private MetadataDialect metadataDialect;

	public static Dimension HGAP30 = new Dimension(30, 1);

	public static Dimension VGAP10 = new Dimension(1, 10);

	EmptyBorder border5 = new EmptyBorder(5, 5, 5, 5);
	EmptyBorder border10 = new EmptyBorder(10, 10, 10, 10);

	private TablesListModel listModel;

	private JFrame frame;

	private ResourceBundle bundle;

	private JPanel mainPanel;

	private JPanel leftPanel;

	private JPanel centerPanel;

	private JComboBox driverCombo;

	private JTextField urlText;

	private JTextField userNameText;

	private JTextField pwdText;

	private JTextField workspaceField;

	private JTextField packageField;

	private JTextField webWorkspaceField;

	private JTextField ctrPackageField;

	private JTextField mappingField;

	private JTextField jspPath;

	private JTextField jspPrefix;

	private JTextField permissionsPrefix;

	private JLabel label;

	private JList list;

	private JCheckBox domainBox;
	private JCheckBox serviceBox;
	private JCheckBox daoBox;
	private JCheckBox controllerBox;
	private JCheckBox jspBox;

	private String databaseName;

	public Generator() {

		setLayout(new BorderLayout());

		setPreferredSize(new Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT));

		add(new JLabel("主面板"), BorderLayout.NORTH);
		// add(new JLabel("WEST"), BorderLayout.WEST);
		add(new JLabel("中心"), BorderLayout.CENTER);
		// add(new JLabel("EAST"), BorderLayout.EAST);
		// add(new JLabel("SOUTH"), BorderLayout.SOUTH);

		// 主窗口
		mainPanel = new JPanel();
		mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.X_AXIS));
		// add(mainPanel);

		mainPanel.add(Box.createRigidArea(HGAP30));

		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		splitPane.setContinuousLayout(true);
		splitPane.setOneTouchExpandable(true);
		add(splitPane);

		// 左边
		leftPanel = new JPanel();
		leftPanel.setLayout(new BorderLayout());
		splitPane.add(leftPanel);

		leftPanel.setBorder(border10);
		leftPanel.add(getDBSetting(), BorderLayout.NORTH);
		leftPanel.add(getWestTables(), BorderLayout.CENTER);

		// mainPanel.add(Box.createRigidArea(HGAP30));
		// 中间
		centerPanel = new JPanel() {
			private static final long serialVersionUID = 1L;
		};
		centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
		splitPane.add(centerPanel);

		// 中上
		JPanel webSettingPanel = new JPanel(new GridLayout(1, 2));
		centerPanel.add(webSettingPanel);
		webSettingPanel.setBorder(border5);

		// web 设置
		webSettingPanel.add(getWebSetting());

		JPanel ctrPanel = new JPanel(new GridLayout(2, 1));
		// ctrPanel.setLayout(new BoxLayout(ctrPanel, BoxLayout.Y_AXIS));
		webSettingPanel.add(ctrPanel);

		ctrPanel.add(getServiceSetting());

		ctrPanel.add(getCheckboxGenerator());

		JButton jButton = new JButton(getString("but.generation"));
		jButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (StringUtils.isBlank(getTableName())) {
					JOptionPane.showMessageDialog(mainPanel, "请先选择一张表！");
					return;
				}
				int result = JOptionPane.showConfirmDialog(mainPanel,
						"确定生成吗？\n你将为[" + list.getSelectedValue().toString() + "]表生成代码！");
				if (result == JOptionPane.YES_OPTION) {
					// 保存设置
					saveSetting();
					// 生成
					try {
						@SuppressWarnings("resource")
						ApplicationContext context = new ClassPathXmlApplicationContext(
								"classpath:spring/applicationContext-main.xml");
						DefaultCodeGeneratorFactory codeGeneratorFactory = (DefaultCodeGeneratorFactory) context
								.getBean("codeGeneratorFactory");
						codeGeneratorFactory.generateTables(getTableName());
						JOptionPane.showMessageDialog(mainPanel, "代码生成成功！");
					} catch (Exception ex) {
						JOptionPane.showMessageDialog(mainPanel, "代码生成失败！\n" + ex.getMessage());
					}
				}

			}
		});

		JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
		jPanel.add(new JLabel(getString("desc.generation")));
		jPanel.add(jButton);
		centerPanel.add(jPanel);

		// 表格
		centerPanel.add(Box.createRigidArea(VGAP10));
		centerPanel.add(getTable());
		centerPanel.setBorder(border5);

		// 加载配置数据
		loadSetting();

	}

	public String getString(String key) {
		String value = "nada";
		if (bundle == null) {
			bundle = ResourceBundle.getBundle("i18n.message");
		}
		try {
			value = bundle.getString(key);
		} catch (MissingResourceException e) {
			log.error("java.util.MissingResourceException: Couldn't find value for: {}", key);
		}
		return value;
	}

	public class TablesListModel extends AbstractListModel {

		private static final long serialVersionUID = 1L;

		private List dataList = Arrays.asList("");

		public void changedList(List dataList) {
			this.dataList = dataList;
			this.fireContentsChanged(this, 0, dataList.size());
		}

		@Override
		public int getSize() {
			return dataList.size();
		}

		@Override
		public Object getElementAt(int index) {
			return dataList.get(index);
		}

	}

	public JComponent getWestTables() {
		list = new JList();
		listModel = new TablesListModel();
		list.setModel(listModel);
		list.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				if (e.getValueIsAdjusting() == false) {
					if (null == metadataDialect) {
						log.warn("not connected db");
						return;
					}
					String dataBaseName = metadataDialect.getDataBase();
					String sql = "select COLUMN_NAME as name, COLUMN_COMMENT AS comments, IS_NULLABLE AS nullable\n from information_schema.COLUMNS where table_name='"
							+ getTableName() + "'"
							+ (dataBaseName != null ? " and table_schema='" + dataBaseName + "'" : "") + ";";
					sql = metadataDialect.colSql(getTableName());
					dt.executeQuery(jdbConnect.getConnection(), jdbConnect.getStatement(), sql);
				}
			}
		});
		list.setVisibleRowCount(22);
		// Add list to a scrollpane
		JScrollPane scrollPane = new JScrollPane(list);
		return scrollPane;
	}

	@SuppressWarnings("unchecked")
	public JComponent getDBSetting() {

		JPanel box = new JPanel();
		box.setLayout(new BoxLayout(box, BoxLayout.X_AXIS));
		JPanel liblePanel = new JPanel(new GridLayout(0, 1)) {
			private static final long serialVersionUID = 1L;

			public Dimension getMaximumSize() {
				return new Dimension(300, super.getMaximumSize().height);
			}
		};
		JPanel textPanel = new JPanel(new GridLayout(0, 1));

		// 驱动
		driverCombo = new JComboBox<Object>(
				new String[] { "org.mariadb.jdbc.Driver", "oracle.jdbc.driver.OracleDriver" });

		label = new JLabel(getString("db.driver"), JLabel.RIGHT);
		label.setLabelFor(driverCombo);

		liblePanel.add(label);
		textPanel.add(driverCombo);

		// jdbc连接串
		urlText = new JTextField();
		// urlText.setColumns(50);

		label = new JLabel(getString("db.url"), JLabel.RIGHT);
		label.setLabelFor(urlText);

		liblePanel.add(label);
		textPanel.add(urlText);

		// 用户名
		userNameText = new JTextField();
		// userNameText.setColumns(10);

		label = new JLabel(getString("db.username"), JLabel.RIGHT);
		label.setLabelFor(userNameText);

		liblePanel.add(label);
		textPanel.add(userNameText);

		// 密码
		pwdText = new JTextField();
		// pwdText.setColumns(10);

		label = new JLabel(getString("db.password"), JLabel.RIGHT);
		label.setLabelFor(pwdText);

		liblePanel.add(label);
		textPanel.add(pwdText);

		JButton connBut = new JButton(getString("but.conn"));
		connBut.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {

				String dbUrl = urlText.getText();
				if (StringUtils.contains(dbUrl, ":mysql:")) {
					metadataDialect = new MysqlMetadataDialectImpl(dbUrl);
				} else if (StringUtils.contains(dbUrl, ":oracle:")) {
					metadataDialect = new OracleMetadataDialectImpl();
				} else {
					throw new IllegalArgumentException("Unknown Database of " + dbUrl);
				}
				String driver = driverCombo.getSelectedItem().toString();
				String user = userNameText.getText();
				String passwd = pwdText.getText();

				jdbConnect = new JDBConnect(dbUrl, driver, user, passwd);
				Vector<Map> vector = jdbConnect.executeQuery(metadataDialect.tablesSql());
				if (null == vector) {
					JOptionPane.showMessageDialog(mainPanel, "连接数据库失败或数据库为空！请检查数据库配置");
					return;
				}
				List list = new LinkedList();
				for (Map map : vector) {
					list.add(map.get("table_name") + (map.get("table_comment") == null ? ""
							: "    << " + map.get("table_comment").toString() + " >>"));
				}
				listModel.changedList(list);

				// 保存设置
				saveDBSetting();
			}
		});
		liblePanel.add(new JLabel());
		textPanel.add(connBut);
		// 布局
		box.add(liblePanel);
		box.add(textPanel);
		return box;
	}

	public JComponent getTable() {
		dt = new JDBCAdapter(new String[] { "查询条件", "列表显示", "编辑", "查看" }, new Object[] { false, false, true, true });
		// dt.executeQuery("select COLUMN_NAME as name, COLUMN_COMMENT AS
		// comments, IS_NULLABLE AS nullable\n from information_schema.COLUMNS
		// where table_name='"+tableName+"';");
		// Create the table
		final JTable tableView = new JTable(dt);

		tableView.getSelectedRow();

		tableView.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				if (e.getValueIsAdjusting() == false) {
				}
			}
		});

		JScrollPane scrollpane = new JScrollPane(tableView);
		scrollpane.setPreferredSize(new Dimension(700, 300));

		return scrollpane;
	}

	public JComponent getWebSetting() {
		JPanel webPanel = new JPanel();
		/*
		 * public Dimension getMaximumSize() { return new
		 * Dimension(super.getMaximumSize().width, 220); };
		 */

		webPanel.setLayout(new BoxLayout(webPanel, BoxLayout.Y_AXIS));
		webPanel.setBorder(new TitledBorder(getString("setting.web.title")));

		JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));

		label = new JLabel(getString("setting.web.work"));
		webWorkspaceField = new JTextField();
		webWorkspaceField.setColumns(30);
		jPanel.add(label);
		jPanel.add(webWorkspaceField);
		webPanel.add(jPanel);

		jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		label = new JLabel(getString("setting.web.ctr.pack"));
		ctrPackageField = new JTextField();
		ctrPackageField.setColumns(30);
		jPanel.add(label);
		jPanel.add(ctrPackageField);
		webPanel.add(jPanel);

		jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		label = new JLabel(getString("setting.web.url"));
		mappingField = new JTextField();
		mappingField.setColumns(30);
		jPanel.add(label);
		jPanel.add(mappingField);
		webPanel.add(jPanel);

		jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		label = new JLabel(getString("setting.web.jsp.path"));
		jspPath = new JTextField();
		jspPath.setColumns(30);
		jPanel.add(label);
		jPanel.add(jspPath);
		webPanel.add(jPanel);

		jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		label = new JLabel(getString("setting.web.jsp.prefix"));
		jspPrefix = new JTextField();
		jspPrefix.setColumns(30);
		jPanel.add(label);
		jPanel.add(jspPrefix);
		webPanel.add(jPanel);

		jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		label = new JLabel(getString("setting.web.permissions.prefix"));
		permissionsPrefix = new JTextField();
		permissionsPrefix.setColumns(30);
		jPanel.add(label);
		jPanel.add(permissionsPrefix);
		webPanel.add(jPanel);

		return webPanel;
	}

	public JComponent getServiceSetting() {
		JPanel servicePanel = new JPanel();
		servicePanel.setBorder(new TitledBorder(getString("setting.service.title")));
		servicePanel.setLayout(new BoxLayout(servicePanel, BoxLayout.Y_AXIS));

		JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));

		label = new JLabel(getString("setting.service.work"));
		workspaceField = new JTextField();
		workspaceField.setColumns(30);
		jPanel.add(label);
		jPanel.add(workspaceField);
		servicePanel.add(jPanel);

		jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		label = new JLabel(getString("setting.service.pack"));
		packageField = new JTextField();
		packageField.setColumns(30);
		jPanel.add(label);
		jPanel.add(packageField);
		servicePanel.add(jPanel);

		return servicePanel;
	}

	public JComponent getCheckboxGenerator() {

		JPanel checkboxPanel = new JPanel();
		checkboxPanel.setLayout(new BoxLayout(checkboxPanel, BoxLayout.Y_AXIS));
		checkboxPanel.setBorder(new TitledBorder(getString("setting.options.title")));
		domainBox = new JCheckBox("domian");
		serviceBox = new JCheckBox("service");
		daoBox = new JCheckBox("dao");
		controllerBox = new JCheckBox("controller");
		jspBox = new JCheckBox("jsp");

		checkboxPanel.add(domainBox);
		checkboxPanel.add(serviceBox);
		checkboxPanel.add(daoBox);
		checkboxPanel.add(controllerBox);
		checkboxPanel.add(jspBox);

		return checkboxPanel;
	}

	private String listOfString(List<String> list) {
		if (list == null || list.size() <= 0) {
			return "";
		}

		StringBuffer strbuf = new StringBuffer();
		for (String str : list) {
			strbuf.append(str).append(",");
		}
		strbuf.setLength(strbuf.length() - 1);

		return strbuf.toString();
	}

	private void saveDBSetting() {
		Map<String, String> map = new HashMap<String, String>();

		String jdbcUrl = urlText.getText();
		map.put("jdbc.url", jdbcUrl);
		map.put("jdbc.username", userNameText.getText());
		map.put("jdbc.password", pwdText.getText());
		map.put("jdbc.driver", driverCombo.getSelectedItem().toString());
		databaseName = jdbcUrl.substring(jdbcUrl.lastIndexOf("/") + 1, jdbcUrl.indexOf("?"));
		map.put("database", databaseName);

		ConfigFileHelper.saveProperties(map);
	}

	private void saveSetting() {
		Map<String, String> map = new HashMap<String, String>();
		map.put("generator.workspace", workspaceField.getText());
		map.put("generator.rootPackage", packageField.getText());

		map.put("generator.web.workspace", webWorkspaceField.getText());
		map.put("generator.web.package", ctrPackageField.getText());
		map.put("generator.page.mapping", mappingField.getText());

		map.put("generator.pagePath", jspPath.getText());
		map.put("generator.page.prefix", jspPrefix.getText());
		map.put("generator.page.permissionsName", permissionsPrefix.getText());

		// optios
		StringBuffer options = new StringBuffer();
		if (domainBox.isSelected()) {
			options.append("domain").append(",");
		}

		if (daoBox.isSelected()) {
			options.append("dao").append(",");
		}

		if (serviceBox.isSelected()) {
			options.append("service").append(",");
		}

		if (controllerBox.isSelected()) {
			options.append("controller").append(",");
		}

		if (jspBox.isSelected()) {
			options.append("page").append(",");
		}
		if (options.length() >= 1) {
			options.setLength(options.length() - 1);
		}
		map.put("generator.options", options.toString());

		//
		Vector rows = dt.getRows();
		List searchList = new ArrayList();
		List listList = new ArrayList();
		List detailList = new ArrayList();
		List viewList = new ArrayList();
		for (int j = 0; j < rows.size(); j++) {
			Vector col = (Vector) rows.get(j);
			if ((Boolean) col.get(3)) {
				// 查询
				searchList.add(col.get(0));
			}

			if ((Boolean) col.get(4)) {
				// 列表
				listList.add(col.get(0));
			}

			if ((Boolean) col.get(5)) {
				// 编辑
				detailList.add(col.get(0));
			}

			if ((Boolean) col.get(6)) {
				// 查看
				viewList.add(col.get(0));
			}
		}
		map.put("generator.page.searchColumns", listOfString(searchList));
		map.put("generator.page.listColumns", listOfString(listList));
		map.put("generator.page.detailColumns", listOfString(detailList));
		map.put("generator.page.viewColumns", listOfString(viewList));

		ConfigFileHelper.saveProperties(map);
	}

	private void loadSetting() {
		Properties p = ConfigFileHelper.loadProperty();
		urlText.setText(p.getProperty("jdbc.url"));
		userNameText.setText(p.getProperty("jdbc.username"));
		pwdText.setText(p.getProperty("jdbc.password"));
		driverCombo.setSelectedItem(p.getProperty("jdbc.driver"));

		workspaceField.setText(p.getProperty("generator.workspace"));
		packageField.setText(p.getProperty("generator.rootPackage"));

		webWorkspaceField.setText(p.getProperty("generator.web.workspace"));
		ctrPackageField.setText(p.getProperty("generator.web.package"));
		mappingField.setText(p.getProperty("generator.page.mapping"));

		jspPath.setText(p.getProperty("generator.pagePath"));
		jspPrefix.setText(p.getProperty("generator.page.prefix"));
		permissionsPrefix.setText(p.getProperty("generator.page.permissionsName"));

		String options = p.getProperty("generator.options");
		if (StringUtils.isNotBlank(options)) {
			for (String str : options.split(",")) {
				if ("domain".equalsIgnoreCase(str.trim())) {
					domainBox.setSelected(true);
				} else if ("dao".equalsIgnoreCase(str.trim())) {
					daoBox.setSelected(true);
				} else if ("service".equalsIgnoreCase(str.trim())) {
					serviceBox.setSelected(true);
				} else if ("controller".equalsIgnoreCase(str.trim())) {
					controllerBox.setSelected(true);
				} else if ("page".equalsIgnoreCase(str.trim())) {
					jspBox.setSelected(true);
				}
			}
		}
	}

	private String getTableName() {
		if (list.getSelectedValue() == null)
			return null;
		return list.getSelectedValue().toString().split("<<")[0].trim();
	}

}
